// 属性的简洁表示
const name = "jinchao";
function sayHello(){
    console.log(`hello ${this.name}`);
}
let person = {
    name,
    sayHello
};
console.log(person);
person.sayHello();

let person1 = {
    name,
    sayHello(){
        console.log(this);
        console.log(this === Object(this));
        console.log(`hello ${this.name}`);
    },
    "person-name": "jinchao"
}
person1.sayHello();

// setter & getter
const person2 = {
    _name: "jinchao",
    get name() {
        return this._name;
    },
    set name(newName) {
        if(typeof newName === "string" && newName) {
            this._name = newName;
        }else {
            console.log(new Error("the new name is not a string type"))
        }
    }
}
person2.name = "jinchao";
console.log(person2);

// 属性名表达式
let myName = "name"
let propNameObj = {
    [myName]: "jinchao",
    ["a" + "ge"]: 18
}
console.log(propNameObj);//{ name: "jinchao", age: 18 }

// 方法名表达式
const SAY_HELLO = "sayHello";
let funcName = {
    [SAY_HELLO](){
        console.log("hello, es6");
    },
    ["p" + "rint"](str){
        console.log(str);
    }
}
funcName[SAY_HELLO]();
funcName.print("hello, world");

// 方法的name属性，返回函数或对象方法的名字
// 对setter 和 getter 返回的是 undefined
console.log(funcName[SAY_HELLO].name); //sayHello
console.log(person2.name.name); //undefined

// Object.is(firstVar, secondVar)
// 1.严格相等判断
// 2.+0 不等于 -0
// 3.NAN 等于自身
console.log(Object.is("name", "name"))
console.log(Object.is({}, {}))//false
console.log(Object.is(NaN, NaN))//true
console.log(Object.is(false, 0)); //false

// Object.assign(targetObj, ...sourceObj); 将所有源对象合并入目标, 类似jquery的extend
// 1.浅拷贝
// 2.同名属性的替换
// 3.只拷贝源对象的自身属性（不拷贝继承属性）
let targetObj =  {
    name: "world",
    person: {}
}
let sourceObj_1 =  {
    person: {
        name: "jinchao",
        son: {
            name: "xiaochao",
            age: 0
        }
    },
    version:"0.0.1",
    num: 0
}
let resultObj = Object.assign(targetObj, sourceObj_1, null);
console.log(targetObj);
console.log(Object.is(resultObj, targetObj)); //true
console.log(Object(null)) //{}

// 4.数组的处理
// 会将数组当做对象，把数组下标当做对象属性，进行处理
console.log(Object.assign([2,3,5],[7,8])); //[7, 8, 5]

// 5.取值函数的处理
// 直接将值取出，并将属性进行拷贝
let getFunc = {
    _name: "chaoshen",
    get name(){
        return this._name;
    },
    set name(newName){
        this._name = newName
    }
}
console.log(Object.assign({}, getFunc));//{_name: "chaoshen", name: "chaoshen"} 

// Object.assign常见用途
// 1.给对象添加属性
class User {
    constructor(name, age){
        Object.assign(this, {name, age});
    }
}
let user = new User("jinchao", 18);
console.log(user); // {name: "jinchao", age: 18}
// 2.给对象添加方法
Object.assign(User.prototype, {
    sayHello(){
        console.log(`Helo ${this.name}`);
    },
    run(){
        console.log("I am running...")
    }
})
user.sayHello();
console.log(Object.getPrototypeOf(user));

// 对象的描述对象
// 针对对象自有属性
console.log(Object.getOwnPropertyDescriptor(user, "name"));
for (const key in user) {
    if (user.hasOwnProperty(key)) {
        const element = user[key];
        console.log(`自有属性: ${key}`);
    }else{
        console.log(`非自有属性: ${key}`);
    }
}
//3.属于深拷贝
let lightTarget = {
    name: "tody"
}
let lightSource = {
    body: "everybody"
}
let lightCopy = Object.assign(lightTarget, lightSource);
lightTarget.body = "anyone";
console.log(lightSource.body);//everbody
lightSource.body = "hh";
console.log(lightCopy.body);//anyone

// Object.keys
console.log(Object.keys(user));
Object.keys(user).forEach((key, index) => {
    console.log(`index: ${index} -> key: ${key}`);
});

console.log(Object.defineProperties);
console.log(user)
// Object.defineProperty回顾
Object.defineProperty(user,"demo", {
    writable: false,//属性的值是否可以被重写
    value: "demo",//属性对应的值
    configurable: true,//是否可以删除目标属性或是否可以再次修改属性的特性
    enumerable: false//此属性是否可以被枚举 for in  Object.keys
})

// 设置对象的原型对象 prototype
Object.setPrototypeOf(user, {
    name: "shasha",
    age: 18,
    sex: "nv"
})
console.log(user.__proto__);

// super关键字，指向对象的原型的对象（父类）
// super关键字表示原型对象时，只能用在对象的方法之中，用在其他地方都会报错。
// 目前，只有对象方法的简写法可以让 JavaScript 引擎确认，定义的是对象的方法。
let superClass = {
    name: "superClass",
    age: 23,
    foo() {
        console.log(this.age);
    }
}
let subClass = {
    age: "18",
    sayHello(){
        console.log(`hello ${super.name}`)
    },
    annotherHello: function(){
        // console.log(`hello ${super.name}`)
    },
    superName(){
        super.foo();//函数中的this 指向子类
    }
}
Object.setPrototypeOf(subClass, superClass);
subClass.sayHello();// hello superClass
// subClass.annotherHello() //'super' keyword unexpected here. 因为annoher并不是一个对象方法，只是对象的属性引用了一个函数而已
subClass.superName()

let myObj = {
    pro1: "pro1_value",
    pro2: "pro2_value",
    pro3: "pro3_value"
}
for(let key of Object.keys(myObj)){
    console.log(key);
}
for(let value of Object.values(myObj)){
    console.log(value);
}
console.log(Object.entries(myObj))
for(let [key, value] of Object.entries(myObj)){
    console.log(`key: ${key}, value: ${value}`);
}


